GPS tracking data for elk (N=31) from Hebblewhite et al 2008 (https://doi.org/10.1890/06-1708.1).
load("./data/elk_gps.rda")
str(elk_gps)
## 'data.frame': 138433 obs. of 6 variables:
## $ timestamp : chr "3/25/2003 19:01:00" "3/25/2003 23:01:00" "3/26/2003 1:01:00" "3/26/2003 5:00:00" ...
## $ location.long : num -115 -115 -115 -115 -115 ...
## $ location.lat : num 51.7 51.7 51.7 51.7 51.7 ...
## $ migration.stage : int 1 1 1 1 1 1 1 1 1 1 ...
## $ sensor.type : chr "gps" "gps" "gps" "gps" ...
## $ individual.local.identifier: chr "GP1" "GP1" "GP1" "GP1" ...
elk_gps$timestamp <- as.POSIXct(elk_gps$timestamp, format="%m/%d/%Y %H:%M:%S")
elk_gps2 <- subset(elk_gps, is.na(timestamp)==FALSE & is.na(location.long)==FALSE & is.na(location.lat)==FALSE)
library(plyr)
library(dplyr)
elk_gps2 |> group_by(individual.local.identifier) |>
summarize(Min_Time = min(timestamp),
Max_Time = max(timestamp),
Duration = round(difftime(max(timestamp), min(timestamp), units = "days")))
## # A tibble: 31 × 4
## individual.local.identifier Min_Time Max_Time Duration
## <chr> <dttm> <dttm> <drtn>
## 1 4049 2001-12-13 07:01:00 2002-11-14 03:00:00 336 days
## 2 GP1 2003-03-25 19:01:00 2003-03-30 01:00:00 4 days
## 3 GP2 2003-03-15 01:00:00 2004-01-04 09:01:00 295 days
## 4 GR104 2004-03-29 19:00:00 2005-01-22 15:00:00 299 days
## 5 GR182 2002-04-05 07:01:00 2002-12-17 17:00:00 256 days
## 6 GR193 2002-04-05 23:01:00 2002-11-23 15:01:00 232 days
## 7 GR196 2002-04-05 23:00:00 2002-06-15 08:30:00 70 days
## 8 YL15 2003-02-16 13:00:00 2004-01-06 05:01:00 324 days
## 9 YL2 2003-02-14 05:00:00 2004-01-14 19:02:00 335 days
## 10 YL25 2003-03-03 22:06:00 2004-03-26 11:00:00 389 days
## # ℹ 21 more rows
elk_gps2 |> group_by(individual.local.identifier) |>
summarize(time_range = as.numeric(difftime(max(timestamp), min(timestamp), units ="days"))) |>
summary()
## individual.local.identifier time_range
## Length:31 Min. : 4.249
## Class :character 1st Qu.:170.636
## Mode :character Median :269.000
## Mean :231.225
## 3rd Qu.:308.727
## Max. :388.538
library(ggplot2)
ggplot(data=elk_gps2,aes(x=timestamp,y=individual.local.identifier,color=individual.local.identifier))+
geom_path(linewidth=1) +
theme_classic() +
xlab("Time") + ylab("ID")+
theme(legend.position = "none")
elk_gps3 <- subset(elk_gps2, !individual.local.identifier %in% c("GP1", "YL72", "YL79"))
elk_gps3 |> group_by(individual.local.identifier) |>
summarize(time_range = as.numeric(difftime(max(timestamp), min(timestamp), units ="days"))) |>
summary()
## individual.local.identifier time_range
## Length:28 Min. : 70.35
## Class :character 1st Qu.:212.72
## Mode :character Median :275.56
## Mean :255.21
## 3rd Qu.:318.69
## Max. :388.54
ggplot(data=elk_gps3,aes(x=timestamp,y=individual.local.identifier,color=individual.local.identifier))+
geom_path(linewidth=1) +
theme_classic() +
xlab("Time") + ylab("ID")+
theme(legend.position = "none")
dtime <- function(t, ...) {difftime(t[-1], t[-length(t)], ...) %>% as.numeric}
fix_rate <- elk_gps3 |>
group_by(individual.local.identifier) |>
arrange(timestamp) |>
mutate(dtime = c(0,round(dtime(timestamp, units ="hours")))) |>
data.frame() |>
ungroup()
barplot(table(fix_rate$dtime))
summary(fix_rate$dtime)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 0.000 1.000 1.152 2.000 1135.000
colnames(elk_gps3) <- c("datetime", "lon", "lat", "mig.stage", "sensor.type", "id")
ggplot(data=elk_gps3, aes(x=lon, y=lat)) +
geom_path(size=0.5, color="darkgrey") +
theme_classic() +
facet_wrap(~id, scale="free", ncol=3)
ggplot(data=elk_gps3, aes(x=datetime, y=lat)) +
geom_path(size=0.5, color="darkgrey") +
theme_classic() +
facet_wrap(~id, scale="free", ncol=3)
library(sf)
elk_sf <- elk_gps3 |>
st_as_sf(coords = c("lon","lat"), crs=4326)
st_geometry(elk_sf)
## Geometry set for 138105 features
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: -116.4028 ymin: 51.38134 xmax: -115.3461 ymax: 52.1541
## Geodetic CRS: WGS 84
## First 5 geometries:
library(mapview)
elk_tracks <- elk_sf |>
group_by(id) |>
summarize(do_union=FALSE) |>
st_cast("LINESTRING")
mapview(elk_tracks, zcol="id")
Data is in UTM Zone 11 North (EPSG Code: 32611)
elk_utm <- elk_sf |>
st_transform(32611)
latlon_coords <- st_coordinates(elk_sf)
xy_coords <- st_coordinates(elk_utm)
elk_df <- elk_utm |> data.frame() |>
select(-geometry)
elk_df$lon <- latlon_coords[,1]
elk_df$lat <- latlon_coords[,2]
elk_df$X <- xy_coords[,1]
elk_df$Y <- xy_coords[,2]
elk_df2 <- elk_df |>
group_by(id) |>
filter(!duplicated(datetime)) |>
arrange(datetime) |>
ungroup() |>
data.frame()
elk_df2$Z <- complex(re = elk_df2$X, im = elk_df2$Y)
# or
elk_df2$Z <- elk_df2$X + 1i*elk_df2$Y
getMovementMetrics <- function(dataframe){
move_step <- diff(dataframe$Z)
time_step <- as.numeric(difftime(dataframe$datetime[-1], dataframe$datetime[-length(dataframe$datetime)], "days"))
absolute_turnangle <- Arg(move_step)
relative_turnangle <- diff(absolute_turnangle)
step_length_km <- Mod(move_step)/1000
dataframe$time_step_days <- c(NA, time_step)
dataframe$move_rate_km_day <- c(NA, step_length_km/time_step)
dataframe$step_length_km <- c(NA, step_length_km)
dataframe$relative_turnangle <- c(NA, NA, relative_turnangle)
return(dataframe)
}
elk_df3 <- elk_df2 |>
ddply("id", getMovementMetrics)
summary(elk_df3$step_length_km)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.00000 0.02128 0.07744 0.23433 0.25010 53.94923 28
elk_df3 |>
group_by(id) |>
filter(is.na(move_rate_km_day)==FALSE) |>
summarize(Min_MoveRate = min(move_rate_km_day),
Max_MoveRate = max(move_rate_km_day),
Avg_MoveRate = mean(move_rate_km_day))
## # A tibble: 28 × 4
## id Min_MoveRate Max_MoveRate Avg_MoveRate
## <chr> <dbl> <dbl> <dbl>
## 1 4049 0 3.82 0.147
## 2 GP2 0 0.0619 0.00317
## 3 GR104 0 0.386 0.00405
## 4 GR182 0 0.128 0.00439
## 5 GR193 0.000173 1.77 0.145
## 6 GR196 0.00000575 0.0504 0.00328
## 7 YL15 0 0.140 0.00290
## 8 YL2 0 0.117 0.00342
## 9 YL25 0 0.142 0.00362
## 10 YL29 0 0.0797 0.00399
## # ℹ 18 more rows
steplengths <- na.omit(elk_df3$step_length_km)
hist(steplengths, col="grey", bor="black", freq=FALSE, breaks=50)
lines(density(steplengths), col=2, lwd=2)
library(circular)
turningangles <- as.circular(na.omit(elk_df3$relative_turnangle))
rose.diag(turningangles, bins=20, col="grey", prop=2)
elk_processed <- elk_df3
save(elk_processed, file="./data/elk_processed.rda")